package cn.git.agent.enhance;

import cn.git.agent.loader.InterceptorInstanceLoader;
import net.bytebuddy.implementation.bind.annotation.*;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

/**
 * @description: 实例方法byteBuddy拦截器
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-12-25
 */
public class InstanceMethodsInterceptor {

    /**
     * 实例方法环绕通知器
     */
    private InstanceMethodAroundInterceptor aroundInterceptor;

    /**
     * 构造方法
     *
     * @param interceptorClassName
     * @param classLoader
     */
    public InstanceMethodsInterceptor(String interceptorClassName,
                                      ClassLoader classLoader) {
        try {
            aroundInterceptor = InterceptorInstanceLoader.load(interceptorClassName, classLoader);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("获取构造方法拦截器失败 ConstructorMethodsInterceptor");
        }
    }

    /**
     * 被标注 RuntimeType 注解的方法就是拦截方法，此时返回的值与返回参数可以与被拦截的方法不一致
     * byteBuddy会在运行期间给被拦截的方法参数进行赋值
     * @return
     */
    @RuntimeType
    public Object intercept(
            @This Object targetObject,
            @Origin Method targetMethod,
            @AllArguments Object[] targetMethodArgs,
            @SuperCall Callable<?> superCall) throws Throwable {
        Object call = null;

        // 获取被拦截对象,用于传递CONTEXT_ATTR_NAME属性
        EnhancedInstance enhancedInstance = (EnhancedInstance) targetObject;

        // 执行后前置方法
        try {
            aroundInterceptor.beforeMethod(enhancedInstance, targetMethod, targetMethodArgs, targetMethod.getParameterTypes());
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("class [" + targetObject.getClass().getName() + "] before exec method [" + targetMethod.getName() + "] interceptor failure [" + e + "]");
        }

        // 执行原方法
        try {
            call = superCall.call();
        } catch (Throwable e) {
            try {
                // 执行异常处理方法
                aroundInterceptor.handleMethodException(enhancedInstance,
                        targetMethod,
                        targetMethodArgs,
                        targetMethod.getParameterTypes(),
                        e);
            } catch (Throwable t) {
                System.out.println("class [" + targetObject.getClass().getName() + "] handle instance [" + targetMethod.getName() + "] interceptor failure [" + e + "]");
                e.printStackTrace();
            }
            throw e;
        } finally {
            try {
                // 执行后置方法
                aroundInterceptor.afterMethod(enhancedInstance,
                        targetMethod,
                        targetMethodArgs,
                        targetMethod.getParameterTypes(),
                        call);
            } catch (Throwable e) {
                e.printStackTrace();
                System.out.println("class [" + targetObject.getClass().getName() + "] after exec method [" + targetMethod.getName() + "] interceptor failure [" + e + "]");
            }
            System.out.println("targetMethodName : " + targetMethod.getName());
        }
        return call;
    }
}
